%%--------------------------------------------------------------------
%% Author: <vjache>
%% Created: 17.03.2009
%% Description: Makes a collection of iterators represented as a 
%%				single iterator. A collection of iterators may be
%%				represented as a list or iterator of iterators.
%%				If collection contains not an iter() item() then
%%				no exception is raised but item returnd as is.
%%--------------------------------------------------------------------
-module(iter_concat).

%%--------------------------------------------------------------------
%% Include files
%%--------------------------------------------------------------------
-include_lib("eunit/include/eunit.hrl").

-include("../include/iter.hrl").
%%--------------------------------------------------------------------
%% Exported Functions
%%--------------------------------------------------------------------
-export([
		 new/1,
		 open/1,
		 next/1,
		 close/1
		 ]).

%%--------------------------------------------------------------------
%% API Functions
%%--------------------------------------------------------------------

new(IterList) when is_list(IterList) ->
	new(iter:from_list(IterList));
new(IterOfIters) when is_record(IterOfIters, iter)->
	iter:from_module(?MODULE, IterOfIters).

open(IterOfIters) ->
	{iter:open(IterOfIters),?EOF}.

next({IOIState,?EOF}) ->
	{IOIState1,NextIter}=iter:next(IOIState),
	case NextIter of
		?EOF ->
			{{IOIState1,?EOF},?EOF};
		NextIter when is_record(NextIter, iter) ->
			next({IOIState1,iter:open(NextIter)});
		_ ->
			{{IOIState1,?EOF},NextIter}
	end;
next({IOIState,CurrIterState}) ->
	{CurrIterState1,Item}=iter:next(CurrIterState),
	case Item of
		?EOF ->
			iter:close(CurrIterState1),
			next({IOIState,?EOF});
		_ ->
			{{IOIState,CurrIterState1},Item}
	end.
close({IOIState,?EOF}) ->
	iter:close(IOIState);
close({IOIState,CurrIterState}) ->
	iter:close(CurrIterState),
	iter:close(IOIState).
%%--------------------------------------------------------------------
%% Local Functions
%%--------------------------------------------------------------------
ioi_test() ->
	TestData=[[1,2,3,4],[5,6,7,8],[9,10,11,12,13,14,15]],
	IOI=new(iter:from_list([iter:from_list(L)||L<-TestData])),
	?assertEqual(lists:sort(lists:flatten(TestData)),lists:sort(iter:to_list(IOI))).
list_test() ->
	TestData=[[1,2,3,4],[5,6,7,8],[9,10,11,12,13,14,15]],
	IOI=new([iter:from_list(L)||L<-TestData]),
	?assertEqual(lists:sort(lists:flatten(TestData)),lists:sort(iter:to_list(IOI))).
mixed_test() ->
	TestData=[[1,2,3,4],[5,6,7,8],[9,10,11,12,13,14,15]],
	IOI=new(iter:from_list([a,b,c,d|[iter:from_list(L)||L<-TestData]])),
	?assertEqual(lists:sort([a,b,c,d|lists:flatten(TestData)]),lists:sort(iter:to_list(IOI))).

